/**
 * Licensed under the MIT License
 *
 * Copyright (c) 2010 Laurent Berthelot
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */
package marcel.display.screen
{
	import flash.display.DisplayObject;
	import flash.display.Stage;
	import flash.geom.Point;
	import marcel.display.Tween;
	
	/**
	 * Defines an object on screen that will be used by the screen manager to position and resize the target display object.
	 * @author	Laurent Berthelot
	 */
	public class ScreenItem
	{
		//--------------------------------------------------------------------------
		//
		//  Public vars
		//
		//--------------------------------------------------------------------------
		/**
		 * The target display object that will be positioned and resized on screen
		 */
		public var target:DisplayObject;
		/**
		 * Indicates the resize tween equation that must be used if resizeDuration is &gt; 0
		 */
		public var resizeEase:Function;
		/**
		 * Indicates the time in seconds of the resize tweening effect. If 0, no tweening is applied.
		 */
		public var resizeDuration:Number = 0;
		/**
		 * Indicates the position tween equation that must be used if slideDuration is &gt; 0
		 */
		public var slideEase:Function;
		/**
		 * Indicates the time in seconds of the position tweening effect. If 0, no tweening is applied.
		 */
		public var slideDuration:Number = 0;
		/**
		 * Indicates if the coordonates position must be rounded or not.
		 */
		public var roundedPosition:Boolean = false;
		
		
		//--------------------------------------------------------------------------
		//
		//  Private vars
		//
		//--------------------------------------------------------------------------
		/**
		 * @private
		 */
		protected var _vAlign:String = "t";
		/**
		 * @private
		 */
		protected var _hAlign:String = "l";
		/**
		 * @private
		 */
		protected var _mp:MarginProps;
		/**
		 * @private
		 */
		protected var _sp:SizeProps;
		/**
		 * @private
		 */
		protected var _pos:Point = new Point();
		
		
		//--------------------------------------------------------------------------
		//
		//  Constructor
		//
		//--------------------------------------------------------------------------
		/**
		 * Constructs a new ScreenItem instance
		 * @param	target			The target display object that will be positioned and resized on screen.
		 * @param	alignType		Indicates how the target must be aligned on screen. Must be a constant of the ScreenAlignTypes class.
		 * @param	margin			A MarginProps instance indicating the margin around the target.
		 * @param	size			A SizeProps instance indicating how the target must be resized.
		 * @param	roundedPosition	Indicates if the coordonates position must be rounded or not.
		 * @see marcel.display.screen.ScreenAlignTypes
		 */
		public function ScreenItem(target:DisplayObject, alignType:String, margin:MarginProps = null, size:SizeProps = null, roundedPosition:Boolean = false) {
			this.target = target;
			_vAlign = alignType.charAt(0);
			_hAlign = alignType.charAt(1);
			_mp = margin === null ? new MarginProps() : margin;
			_sp = size === null ? new SizeProps(target.width, target.height, false, false) : size;
			this.roundedPosition = roundedPosition;
		}
		
		
		//--------------------------------------------------------------------------
		//
		//  Public methods
		//
		//--------------------------------------------------------------------------
		/**
		 * Updates the size and position of the target
		 * @param	stage		The stage reference to get the size from
		 * @param	forceNoTween	Indicates if the tween effect must not be applied, for example on the first call.
		 */
		public function update(stage:Stage, forceNoTween:Boolean = false):void {
			var sw:uint = stage.stageWidth;
			var sh:uint = stage.stageHeight;
			_sp.updateProperties(sw, sh);
			_mp.updateProperties(sw, sh);
			// UPDATE SIZE
			if (_sp.resize) {
				// HORIZONTAL
				var _hMargin:Number = _mp.left + _mp.right;
				if (_sp.width + _hMargin >= sw) {
					_sp.width = sw - _hMargin;
				}
				// VERTICAL
				var _vMargin:Number = _mp.top + _mp.bottom;
				if (_sp.height + _vMargin >= sh) {
					_sp.height = sh - _vMargin;
				}
			}
			// UPDATE POSITION
			switch (_hAlign) {
				default :
				case "l" :
					_pos.x = _mp.left;
					break;
				case "c" :
					_pos.x = _mp.left - _mp.right + (sw - _sp.width) * .5;
					break;
				case "r" :
					_pos.x = sw - _sp.width - _mp.right;
					break;
			}
			switch (_vAlign) {
				default :
				case "t" :
					_pos.y = _mp.top;
					break;
				case "m" :
					_pos.y = _mp.top - _mp.bottom + ((sh - _sp.height) >> 1);
					break;
				case "b" :
					_pos.y = sh - _sp.height - _mp.bottom;
					break;
			}
			if (_sp.resize) {
				if (!forceNoTween && resizeDuration > 0) {
					Tween.resizeTo(target, new Point(_sp.width, _sp.height), resizeDuration, resizeEase);
				} else {
					target.width = _sp.width;
					target.height = _sp.height;
				}
			}
			
			if (roundedPosition) _pos = new Point(Math.round(_pos.x), Math.round(_pos.y));
			
			if (!forceNoTween && slideDuration > 0) {
				Tween.moveTo(target, _pos, slideDuration, slideEase);
			} else {
				target.x = _pos.x;
				target.y = _pos.y;
			}
			
			
		}
	}
}